From 4f863ad2277e7a7c9cadf1b743db2b36a3f30c38 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 10 Jun 2010 11:18:02 +0100 Subject: [PATCH] VMX: enforce EPT paging structure memory type and page-walk length check. Also use a macro to get EPT walk length. signed-off-by: Xin Li --- xen/arch/x86/hvm/vmx/vmcs.c | 25 ++++++++++++++++++++----- xen/arch/x86/hvm/vmx/vmx.c | 9 ++++++--- xen/arch/x86/mm/hap/p2m-ept.c | 14 ++++++-------- xen/include/asm-x86/hvm/vmx/vmcs.h | 23 +++++++++++------------ xen/include/asm-x86/hvm/vmx/vmx.h | 14 ++++++++++++++ 5 files changed, 57 insertions(+), 28 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index e1de38cc94..e97d0ed179 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -192,6 +192,26 @@ static int vmx_init_vmcs_config(void) MSR_IA32_VMX_PROCBASED_CTLS2, &mismatch); } + /* The IA32_VMX_EPT_VPID_CAP MSR exists only when EPT or VPID available */ + if ( _vmx_secondary_exec_control & (SECONDARY_EXEC_ENABLE_EPT | + SECONDARY_EXEC_ENABLE_VPID) ) + { + rdmsrl(MSR_IA32_VMX_EPT_VPID_CAP, _vmx_ept_vpid_cap); + + /* + * Additional sanity checking before using EPT: + * 1) the CPU we are running on must support EPT WB, as we will set + * ept paging structures memory type to WB; + * 2) the CPU must support the EPT page-walk length of 4 according to + * Intel SDM 25.2.2. + * + * Or we just don't use EPT. + */ + if ( !(_vmx_ept_vpid_cap & VMX_EPT_MEMORY_TYPE_WB) || + !(_vmx_ept_vpid_cap & VMX_EPT_WALK_LENGTH_4_SUPPORTED) ) + _vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_EPT; + } + if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT ) { /* @@ -210,11 +230,6 @@ static int vmx_init_vmcs_config(void) SECONDARY_EXEC_UNRESTRICTED_GUEST); } - /* The IA32_VMX_EPT_VPID_CAP MSR exists only when EPT or VPID available */ - if ( _vmx_secondary_exec_control & - (SECONDARY_EXEC_ENABLE_EPT | SECONDARY_EXEC_ENABLE_VPID) ) - rdmsrl(MSR_IA32_VMX_EPT_VPID_CAP, _vmx_ept_vpid_cap); - if ( (_vmx_secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING) && ple_gap == 0 ) { diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index ae26706581..7653d906f1 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -78,12 +78,15 @@ static int vmx_domain_initialise(struct domain *d) { int rc; - d->arch.hvm_domain.vmx.ept_control.etmt = EPT_DEFAULT_MT; - d->arch.hvm_domain.vmx.ept_control.gaw = EPT_DEFAULT_GAW; + /* Set the memory type used when accessing EPT paging structures. */ + d->arch.hvm_domain.vmx.ept_control.ept_mt = EPT_DEFAULT_MT; + + /* set EPT page-walk length, now it's actual walk length - 1, i.e. 3 */ + d->arch.hvm_domain.vmx.ept_control.ept_wl = 3; + d->arch.hvm_domain.vmx.ept_control.asr = pagetable_get_pfn(p2m_get_pagetable(p2m_get_hostp2m(d))); - if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 ) return rc; diff --git a/xen/arch/x86/mm/hap/p2m-ept.c b/xen/arch/x86/mm/hap/p2m-ept.c index 0fb306b7c3..2e2f6621f9 100644 --- a/xen/arch/x86/mm/hap/p2m-ept.c +++ b/xen/arch/x86/mm/hap/p2m-ept.c @@ -253,7 +253,7 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, ASSERT(table != NULL); - for ( i = EPT_DEFAULT_GAW; i > walk_level; i-- ) + for ( i = ept_get_wl(d); i > walk_level; i-- ) { ret = ept_next_level(d, 0, &table, &gfn_remainder, i * EPT_TABLE_ORDER); if ( !ret ) @@ -402,7 +402,7 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t, /* Should check if gfn obeys GAW here. */ - for ( i = EPT_DEFAULT_GAW; i > 0; i-- ) + for ( i = ept_get_wl(d); i > 0; i-- ) { retry: ret = ept_next_level(d, 1, &table, &gfn_remainder, @@ -492,7 +492,7 @@ static ept_entry_t ept_get_entry_content(struct domain *d, unsigned long gfn, in if ( gfn > d->arch.p2m->max_mapped_pfn ) goto out; - for ( i = EPT_DEFAULT_GAW; i > 0; i-- ) + for ( i = ept_get_wl(d); i > 0; i-- ) { ret = ept_next_level(d, 1, &table, &gfn_remainder, i * EPT_TABLE_ORDER); @@ -531,7 +531,7 @@ void ept_walk_table(struct domain *d, unsigned long gfn) goto out; } - for ( i = EPT_DEFAULT_GAW; i >= 0; i-- ) + for ( i = ept_get_wl(d); i >= 0; i-- ) { ept_entry_t *ept_entry, *next; u32 index; @@ -658,8 +658,6 @@ static void ept_change_entry_type_global(struct domain *d, p2m_type_t ot, if ( pagetable_get_pfn(p2m_get_pagetable(p2m_get_hostp2m(d))) == 0 ) return; - BUG_ON(EPT_DEFAULT_GAW != 3); - l4e = map_domain_page(mfn_x(pagetable_get_mfn(p2m_get_pagetable(p2m_get_hostp2m(d))))); for (i4 = 0; i4 < EPT_PAGETABLE_ENTRIES; i4++ ) { @@ -751,7 +749,7 @@ static void ept_dump_p2m_table(unsigned char key) int order; int i; int is_pod; - int ret; + int ret = 0; unsigned long index; unsigned long gfn, gfn_remainder; unsigned long record_counter = 0; @@ -772,7 +770,7 @@ static void ept_dump_p2m_table(unsigned char key) table = map_domain_page(mfn_x(pagetable_get_mfn(p2m_get_pagetable(p2m)))); - for ( i = EPT_DEFAULT_GAW; i > 0; i-- ) + for ( i = ept_get_wl(d); i > 0; i-- ) { ret = ept_next_level(d, 1, &table, &gfn_remainder, i * EPT_TABLE_ORDER); diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index b49479b173..d7ad8f03ec 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -55,23 +55,25 @@ struct vmx_msr_state { unsigned long msrs[VMX_MSR_COUNT]; }; -#define EPT_DEFAULT_MT 6 -#define EPT_DEFAULT_GAW 3 +#define EPT_DEFAULT_MT MTRR_TYPE_WRBACK struct vmx_domain { unsigned long apic_access_mfn; union { struct { - u64 etmt :3, - gaw :3, - rsvd :6, - asr :52; + u64 ept_mt :3, + ept_wl :3, + rsvd :6, + asr :52; }; u64 eptp; } ept_control; cpumask_t ept_synced; }; +#define ept_get_wl(d) \ + ((d)->arch.hvm_domain.vmx.ept_control.ept_wl) + struct arch_vmx_struct { /* Virtual address of VMCS. */ struct vmcs_struct *vmcs; @@ -174,8 +176,9 @@ extern u32 vmx_secondary_exec_control; extern bool_t cpu_has_vmx_ins_outs_instr_info; -extern u64 vmx_ept_vpid_cap; - +#define VMX_EPT_WALK_LENGTH_4_SUPPORTED 0x00000040 +#define VMX_EPT_MEMORY_TYPE_UC 0x00000100 +#define VMX_EPT_MEMORY_TYPE_WB 0x00004000 #define VMX_EPT_SUPERPAGE_2MB 0x00010000 #define VMX_EPT_SUPERPAGE_1GB 0x00020000 @@ -193,10 +196,6 @@ extern u64 vmx_ept_vpid_cap; (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) #define cpu_has_vmx_ept \ (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) -#define cpu_has_vmx_ept_1gb \ - (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_1GB) -#define cpu_has_vmx_ept_2mb \ - (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_2MB) #define cpu_has_vmx_vpid \ (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_VPID) #define cpu_has_monitor_trap_flag \ diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index 7450ffead9..81e898884e 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -184,6 +184,20 @@ void vmx_update_debug_state(struct vcpu *v); #define MODRM_EAX_07 ".byte 0x38\n" /* [EAX], with reg/opcode: /7 */ #define MODRM_EAX_ECX ".byte 0xc1\n" /* EAX, ECX */ +extern u64 vmx_ept_vpid_cap; + +#define cpu_has_vmx_ept_wl4_supported \ + (vmx_ept_vpid_cap & VMX_EPT_WALK_LENGTH_4_SUPPORTED) +#define cpu_has_vmx_ept_mt_uc \ + (vmx_ept_vpid_cap & VMX_EPT_MEMORY_TYPE_UC) +#define cpu_has_vmx_ept_mt_wb \ + (vmx_ept_vpid_cap & VMX_EPT_MEMORY_TYPE_WB) +#define cpu_has_vmx_ept_1gb \ + (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_1GB) +#define cpu_has_vmx_ept_2mb \ + (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_2MB) + + static inline void __vmptrld(u64 addr) { asm volatile ( VMPTRLD_OPCODE -- 2.30.2